/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package biofilter.filters;

import biofilter.exceptions.InvalidRecordException;
import biofilter.records.FileNameRecord;
import biofilter.records.Record;
import biofilter.records.Record;
import biofilter.util.SystemProperties;
import biofilter.util.ProcessHandler;
import biofilter.util.ProcessUtil;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * bowtie -f -v 1 -a genomes/allBurk ./reads/Reads1.fasta -p 4 --best >> bowtieResults/R1_1SEQ.bowtie
 * bowtie [options]* <ebwt> {-1 <m1> -2 <m2> | --12 <r> | <s>} [<hit>]
 *
 * <ebwt>  A bowtie formatted reference built using bowtie-build specified by
 *         the base name.
 * <m1>    Comma-separated list of files containing upstream mates (or the
 *         sequences themselves, if -c is set) paired with mates in <m2>
 * <m2>    Comma-separated list of files containing downstream mates (or the
 *         sequences themselves if -c is set) paired with mates in <m1>
 * <r>     Comma-separated list of files containing Crossbow-style reads.  Can be
 *         a mixture of paired and unpaired.  Specify "-" for stdin.
 * <s>     Comma-separated list of files containing unpaired reads, or the
 *         sequences themselves, if -c is set.  Specify "-" for stdin.
 * <hit>   File to write hits to (default: stdout)
 *
 * -f                 query input files are (multi-)FASTA .fa/.mfa
 * -v <int>           report end-to-end hits w/ <=v mismatches; ignore qualities
 * -a/--all           report all alignments per read (much slower than low -k)
 * -p/--threads <int> number of alignment threads to launch (default: 1)
 * --best             hits guaranteed best stratum; ties broken by quality
 *
 * @author Thomas S. Brettin
 */
public class BowtieFilter extends SimpleFilter {

    private String options = "";
    private SystemProperties sysprop = null;
    public BowtieFilter(){
        super();
        setup();
    }
    public BowtieFilter(String opts){
        super();
        setOptions(opts);
        setup();
    }

    public void setup(){
        try {
            sysprop = new SystemProperties();
            setTmp( sysprop.get("tmp") );
            setBowTieEXE( sysprop.get("bowtie"));
            this.bowdir = this.tempDir;
        } catch (IOException ex) {
            Logger.getLogger(BowtieFilter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void setOptions(String o) {
        this.options = o;
    }
    private String ebwt = null;

    public void setEbwt(String e) {
        if (e == null) {
            throw new IllegalArgumentException("arg to setEbwt is null");
        }
        this.ebwt = e;
    }
    /**
     * The hit file is the output file for a set of reads (an alignment file)
     */
    private String hitFileName;
    public void setHitFileName(String h) {
        this.hitFileName = h;
    }

    private void setHitName(){
        ProcessUtil pu = new ProcessUtil();
        this.hitFileName = pu.getUniqueFileName(".bowtie");
    }

    String bowtieEXE = null;
    public void setBowTieEXE(String bowtieEXEPath){
        this.bowtieEXE = bowtieEXEPath;
    }

    /**
     * Set the temporary directory for placing data
     */
    private String tempDir = null;
    public void setTmp(String tempDir){
        this.tempDir = tempDir;
        if (!this.tempDir.endsWith("/")){
            this.tempDir = tempDir + "/";
        }
    }

    private String bowdir = null;

    @Override
    protected Record transformRecord(Record r) throws InvalidRecordException {
        StringBuffer stdOut = null;
        StringBuffer stdErr = null;

        try {
            this.transformedRecord = null;
            if (!(r instanceof FileNameRecord)) {
                throw new RuntimeException("type mismatch, expected FileNameRecord");
            }if(r == null){
                throw new RuntimeException("FileNameRecord is null!");
            }if(hitFileName == null){
                this.setHitName();
            }

            stdOut = new StringBuffer();
            stdErr = new StringBuffer();

            /**
             * Usage:
                  bowtie [options]* <ebwt> {-1 <m1> -2 <m2> | --12 <r> | <s>} [<hit>]

                  <m1>    Comma-separated list of files containing upstream mates (or the
                          sequences themselves, if -c is set) paired with mates in <m2>
                  <m2>    Comma-separated list of files containing downstream mates (or the
                          sequences themselves if -c is set) paired with mates in <m1>
                  <r>     Comma-separated list of files containing Crossbow-style reads.  Can be
                          a mixture of paired and unpaired.  Specify "-" for stdin.
                  <s>     Comma-separated list of files containing unpaired reads, or the
                          sequences themselves, if -c is set.  Specify "-" for stdin.
                  <hit>   File to write hits to (default: stdout)
             */
            String command = this.bowtieEXE + " " + options + " " + ebwt + " " + r.get() + " " + this.bowdir + hitFileName;

            Logger.getLogger(BowtieFilter.class.getName()).log(Level.INFO, "Running command: " + command);
            Logger.getLogger(BowtieFilter.class.getName()).log(Level.INFO, "Bowtie File created: " + this.bowdir + hitFileName);
            int pid = ProcessHandler.runCommand(command, stdOut, stdErr);

        } catch (IOException ex) {
            Logger.getLogger(BowtieFilter.class.getName()).log(Level.SEVERE, null, ex);
            throw new InvalidRecordException(ex.getMessage());
        } catch (InterruptedException ex) {
            Logger.getLogger(BowtieFilter.class.getName()).log(Level.SEVERE, null, ex);
            throw new InvalidRecordException(ex.getMessage());
        }

        return (new FileNameRecord(this.tempDir + hitFileName));
    }

    public Record peek() throws InvalidRecordException {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
